package com.faxsun.admin.service;

import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.broadleafcommerce.core.catalog.dao.CategoryDao;
import org.broadleafcommerce.core.catalog.dao.ProductDao;
import org.broadleafcommerce.core.catalog.domain.Category;
import org.broadleafcommerce.core.catalog.domain.Product;
import org.broadleafcommerce.core.catalog.domain.ProductAttribute;
import org.broadleafcommerce.core.catalog.domain.Sku;
import org.broadleafcommerce.core.order.domain.OrderItemAttribute;
import org.springframework.stereotype.Service;

import com.faxsun.core.catalog.domain.FSSku;
import com.faxsun.core.catalog.domain.FSSkuImpl;
import com.faxsun.core.catalog.service.FSProductService;
import com.faxsun.core.order.dao.FSOrderItemDao;

@Service("treasuerService")
public class TreasureServiceImpl implements TreasureService {

	@Resource(name = "blProductDao")
	ProductDao productDao;

	@Resource(name = "fsProductService")
	FSProductService fsProductService;

	@Resource(name = "blCategoryDao")
	CategoryDao categoryDao;

	@Resource(name = "blOrderItemDao")
	FSOrderItemDao fsOrderItemDao;

	private static final TreasureCompartor compartor = new TreasureCompartor();

	@Override
	public Long generateWinningNumberForProduct(Product product, Long seedNumber, Integer... range) {

		Sku sku = product.getDefaultSku();
		if (sku instanceof FSSku) {

			FSSku fsSku = (FSSku) sku;
			Integer moduleNumber = range.length > 0 ? range[0] : fsSku.getQuantityTotal();

			return moduleNumber.intValue() == 0 ? Long.valueOf(0) : fsSku.getId() * 10000 + 1
					+ (seedNumber * 10000) % moduleNumber;
		}
		return Long.valueOf(0);
	}

	@Override
	public void setWinningNumberForProduct(Product product, Long winningNumber) throws Exception {

		if (product.getDefaultSku().getQuantityAvailable() > 0) {
			throw new Exception("Inventory not 0.");
		}
		Map<String, ProductAttribute> attributes = product.getProductAttributes();
		ProductAttribute attribute = attributes.get(TreasureConstants.WINNING_NUMBER);
		if (attribute == null) {
			attribute = fsProductService.createProductAttribute();
			attribute.setProduct(product);
			attribute.setName(TreasureConstants.WINNING_NUMBER);
			attribute.setValue(winningNumber.toString());
			attributes.put(TreasureConstants.WINNING_NUMBER, attribute);
			fsProductService.saveProduct(product);
		} else {
			attribute.setValue(winningNumber.toString());
			fsProductService.saveProductAttribute(attribute);
		}

	}

	@Override
	public void findAndSaveTreasureWinnerByProduct(Product product,
			List<OrderItemAttribute> orderItemAttributes) {
		Map<String, ProductAttribute> attributes = product.getProductAttributes();

		ProductAttribute winningNumberAttribute = attributes.get(TreasureConstants.WINNING_NUMBER);
		Long winnerCustomerId = null;
		if (winningNumberAttribute != null) {
			String winningNumber = winningNumberAttribute.getValue();

			// List<OrderItemAttribute> orderItemAttributes = fsOrderItemDao
			// .readAllOrderItemAttributesBySku(product.getDefaultSku());

			OrderItemAttribute winnerAttribute = null;
			// FIXME: Shall we use the binary search to get the result faster?
			// Collections.binarySearch(orderItemAttributes, key)
			for (OrderItemAttribute orderItemAttribute : orderItemAttributes) {
				if (orderItemAttribute.getValue().equals(winningNumber)) {
					winnerAttribute = orderItemAttribute;
					break;
				}
			}

			if (winnerAttribute != null) {
				winnerCustomerId = winnerAttribute.getOrderItem().getOrder().getCustomer().getId();
			}
		}

		ProductAttribute winnerCustomerIdAttribute = attributes.get(TreasureConstants.WINNER_CUSTOMER_ID);
		if (winnerCustomerId != null) {
			if (winnerCustomerIdAttribute == null) {
				winnerCustomerIdAttribute = fsProductService.createProductAttribute();
				winnerCustomerIdAttribute.setProduct(product);
				winnerCustomerIdAttribute.setName(TreasureConstants.WINNER_CUSTOMER_ID);
				winnerCustomerIdAttribute.setValue(winnerCustomerId.toString());
				attributes.put(TreasureConstants.WINNER_CUSTOMER_ID, winnerCustomerIdAttribute);
				fsProductService.saveProduct(product);
			} else {
				winnerCustomerIdAttribute.setValue(winnerCustomerId.toString());
				fsProductService.saveProductAttribute(winnerCustomerIdAttribute);
			}
		} else {
			if (winnerCustomerIdAttribute != null) {
				// attributes.remove(TreasureConstants.WINNER_CUSTOMER_ID);
				// fsProductService.removeProductAttribute(winnerCustomerIdAttribute);
				winnerCustomerIdAttribute.setValue("0");
				fsProductService.saveProductAttribute(winnerCustomerIdAttribute);
			}
		}
	}

	@Override
	public List<Product> list() {

		Category category = categoryDao.findCategoryByURI("/treasure");
		List<Product> products = productDao.readActiveProductsByCategory(category.getId());
		Collections.sort(products, compartor);

		return products;
	}

}

class TreasureCompartor implements Comparator<Product> {

	@SuppressWarnings("unused")
	@Override
	public int compare(Product o1, Product o2) {

		Map<String, ProductAttribute> o1Attribute = o1.getProductAttributes();
		Map<String, ProductAttribute> o2Attribute = o2.getProductAttributes();

		FSSkuImpl sku1 = (FSSkuImpl) o1.getDefaultSku();
		FSSkuImpl sku2 = (FSSkuImpl) o2.getDefaultSku();

		Integer quantity1 = sku1.getQuantityAvailable();
		Integer quantity2 = sku2.getQuantityAvailable();

		// boolean isWaitResult1 = quantity1.equals(new Integer(0)) &&
		// (o1Attribute.size() == 0);
		// boolean isWaitResult2 = quantity2.equals(new Integer(0)) &&
		// (o2Attribute.size() == 0);

		return quantity1 - quantity2;

		// if (isWaitResult1 && isWaitResult2) {
		// return quantity1-quantity2;
		// } else if (!isWaitResult1 && !isWaitResult2) {
		// return 0;
		// } else if (isWaitResult1 && !isWaitResult2) {
		// return -1;
		// } else if (isWaitResult2 && !isWaitResult1) {
		// return 1;
		// }
		// return 0;
	}

}
